/*******************************************************************************
 * Copyright (c) 2000, 2004 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
module dwt.internal.compatibility;


private import dwt.dwt;
 
private import dwt.util.util;

private import tango.core.Exception;
private import tango.text.convert.Format;
private import TangoFile = tango.io.device.File;
static import tango.sys.Environment;
import dwt.internal.converter;

alias Exception StreamException;

void implMissing(T, X)(T t, X x){
	
}

public class File {

    public static char separatorChar;
    public static String separator;
    public static char pathSeparatorChar;
    public static String pathSeparator;

    private tango.io.FilePath.FilePath mFilePath;

    static this(){
        separator = tango.io.model.IFile.FileConst.PathSeparatorString;
        separatorChar = tango.io.model.IFile.FileConst.PathSeparatorChar;
        pathSeparator = tango.io.model.IFile.FileConst.SystemPathString;
        pathSeparatorChar = tango.io.model.IFile.FileConst.SystemPathChar;
    }

    public this ( String pathname ){
        mFilePath = new tango.io.FilePath.FilePath( tango.io.Path.standard( pathname ));
    }

    public this ( String parent, String child ){
        mFilePath = new tango.io.FilePath.FilePath( tango.io.FilePath.FilePath.join( parent, child ) );
    }

    public this ( File parent, String child ){
        mFilePath = new tango.io.FilePath.FilePath( tango.io.FilePath.FilePath.join( parent.mFilePath.toString, child ) );
    }

    public int getPrefixLength(){
        implMissing( __FILE__, __LINE__ );
        return 0;
    }

    public String getName(){
        implMissing( __FILE__, __LINE__ );
        return null;
    }

    public String getParent(){
        implMissing( __FILE__, __LINE__ );
        return null;
    }

    public File getParentFile(){
        implMissing( __FILE__, __LINE__ );
        return null;
    }

    public String getPath(){
        implMissing( __FILE__, __LINE__ );
        return null;
    }

    public bool isAbsolute(){
        implMissing( __FILE__, __LINE__ );
        return false;
    }

    public String getAbsolutePath(){
            if ( mFilePath.isAbsolute ) return mFilePath.toString;
            else return mFilePath.absolute( tango.sys.Environment.Environment.cwd ).toString;
    }

    public File getAbsoluteFile(){
        return new File( getAbsolutePath() );
    }

    public String getCanonicalPath(){
        implMissing( __FILE__, __LINE__ );
        return null;
    }

    public File getCanonicalFile(){
        implMissing( __FILE__, __LINE__ );
        return null;
    }

    public bool canRead(){
        implMissing( __FILE__, __LINE__ );
        return false;
    }

    public bool canWrite(){
        return mFilePath.isWritable;
    }

    public bool exists(){
        return mFilePath.exists;
    }

    public bool isDirectory(){
        return mFilePath.isFolder;
    }

    public bool isFile(){
        implMissing( __FILE__, __LINE__ );
        return false;
    }

    public bool isHidden(){
        implMissing( __FILE__, __LINE__ );
        return false;
    }

    public long lastModified(){
        implMissing( __FILE__, __LINE__ );
        return 0L;
    }

    public long length(){
        implMissing( __FILE__, __LINE__ );
        return 0L;
    }

    public bool createNewFile(){
        implMissing( __FILE__, __LINE__ );
        return false;
    }

    public bool delete_KEYWORDESCAPE(){
        implMissing( __FILE__, __LINE__ );
        return false;
    }

    public void deleteOnExit(){
        implMissing( __FILE__, __LINE__ );
    }

    public String[] list(){
        implMissing( __FILE__, __LINE__ );
        return null;
    }

    public File[] listFiles(){
        implMissing( __FILE__, __LINE__ );
        return null;
    }

    public bool mkdir(){
        implMissing( __FILE__, __LINE__ );
        return false;
    }

    public bool mkdirs(){
        implMissing( __FILE__, __LINE__ );
        return false;
    }

    public bool renameTo( File dest ){
        implMissing( __FILE__, __LINE__ );
        return false;
    }

    public bool setLastModified( long time ){
        implMissing( __FILE__, __LINE__ );
        return false;
    }

    public bool setReadOnly(){
        implMissing( __FILE__, __LINE__ );
        return false;
    }

    public static File[] listRoots(){
        implMissing( __FILE__, __LINE__ );
        return null;
    }

    public static File createTempFile( String prefix, String suffix, File directory ){
        implMissing( __FILE__, __LINE__ );
        return null;
    }

    public static File createTempFile( String prefix, String suffix ){
        implMissing( __FILE__, __LINE__ );
        return null;
    }

    public int compareTo( File pathname ){
        implMissing( __FILE__, __LINE__ );
        return 0;
    }

    public String toString(){
        implMissing( __FILE__, __LINE__ );
        return null;
    }


}

public abstract class InputStream {
    public this (){
    }

    public abstract int read();

    public int read( byte[] b ){
        foreach( uint idx, inout byte val; b ){
            int c = read();
            if( c == -1 ){
                return ( idx == 0 ) ? -1 : idx;
            }
            b[ idx] = cast(byte)( c & 0xFF );
        }
        return b.length;
    }

    public int read( byte[] b, int off, int len ){
        return read( b[ off .. off+len ] );
    }

    public long skip( long n ){
        implMissing( __FILE__, __LINE__ );
        return 0L;
    }

    public int available(){
        return 0;
    }

    public void close(){
        implMissing( __FILE__, __LINE__ );
    }

    public synchronized void mark( int readlimit ){
        implMissing( __FILE__, __LINE__ );
    }

    public synchronized void reset(){
        implMissing( __FILE__, __LINE__ );
    }

    public bool markSupported(){
        implMissing( __FILE__, __LINE__ );
        return false;
    }


}

abstract class OutputStream {

    public this(){
    }

    public abstract void write( int b );

    public void write( byte[] b ){
        foreach( bv; b ){
            write(bv);
        }
    }

    public void write( byte[] b, int off, int len ){
        write(b[off .. off+len]);
    }

    public void flush(){
    }

    public void close(){
    }
}


public class MemoryStreamX : InputStream{
	ubyte[] dat;
	int pos;
	this(ubyte[] _da){
		dat	= _da;
	}
	int read(){
		if( pos >= dat.length ){
			return -1;
		}
		return dat[pos++];
	}
}

public class FileInputStream : InputStream {

    alias InputStream.read read;

    private TangoFile.File conduit;
    private ubyte[] buffer;
    private int buf_pos;
    private int buf_size;
    private const int BUFFER_SIZE = 0x10000;
    private bool eof;

    public this ( char[] name ){
        conduit = new TangoFile.File( name );
        buffer = new ubyte[]( BUFFER_SIZE );
    }

    public this ( File file ){
        implMissing( __FILE__, __LINE__ );
        conduit = new TangoFile.File( file.getAbsolutePath(), TangoFile.File.ReadExisting );
        buffer = new ubyte[]( BUFFER_SIZE );
    }

    public override int read(){
        if( eof ){
            return -1;
        }
        try{
            if( buf_pos == buf_size ){
                buf_pos = 0;
                buf_size = conduit.input.read( buffer );
            }
            if( buf_size <= 0 ){
                eof = true;
                return -1;
            }
            assert( buf_pos < BUFFER_SIZE, Format( "{0} {1}", buf_pos, buf_size ) );
            assert( buf_size <= BUFFER_SIZE );
            int res = cast(int) buffer[ buf_pos ];
            buf_pos++;
            return res;
        }
        catch( IOException e ){
            eof = true;
            return -1;
        }
    }

    public long skip( long n ){
        implMissing( __FILE__, __LINE__ );
        return 0L;
    }

    public int available(){
        implMissing( __FILE__, __LINE__ );
        return 0;
    }

    public override void close(){
        conduit.close();
    }
}




public class FileOutputStream : OutputStream {

    alias OutputStream.write write;
    alias OutputStream.close close;
    TangoFile.File fc;
    
    public this ( String name ){
        fc = new TangoFile.File( name, TangoFile.File.WriteCreate );
    }

    public this ( String name, bool append ){
        fc = new TangoFile.File( name, append ? TangoFile.File.WriteAppending : TangoFile.File.WriteCreate );
    }

    public this ( File file ){
        this( file.toString );
    }

    public this ( File file, bool append ){
        this( file.toString, append );
    }

    public override void write( int b ){
        ubyte[1] a;
        a[0] = b & 0xFF;
        fc.write(a);
    }

    public override void close(){
        fc.close();
    }

    public void finalize(){
        implMissing( __FILE__, __LINE__ );
    }


}


/**
 * This class is a placeholder for utility methods commonly
 * used on J2SE platforms but not supported on some J2ME
 * profiles.
 * <p>
 * It is part of our effort to provide support for both J2SE
 * and J2ME platforms.
 * </p>
 * <p>
 * IMPORTANT: some of the methods have been modified from their
 * J2SE parents. Refer to the description of each method for 
 * specific changes.
 * </p>
 * <ul>
 * <li>Exceptions thrown may differ since J2ME's set of 
 * exceptions is a subset of J2SE's one.
 * </li>
 * <li>The range of the mathematic functions is subject to
 * change.
 * </li>		
 * </ul>
 */
public class Compatibility {

	private import tango.math.Math : PI_ = PI	;
	private import tango.stdc.math;
	
	alias PI_ PI;
	
	static double toRadians = PI / 180;
	
	public static InputStream newFileInputStream(String filename) {
	    return new FileInputStream(filename);
	}

/**
 * Answers the length of the side adjacent to the given angle
 * of a right triangle. In other words, it returns the integer
 * conversion of length * cos (angle).
 * <p>
 * IMPORTANT: the j2me version has an additional restriction on
 * the argument. length must be between -32767 and 32767 (inclusive).
 * </p>
 * 
 * @param angle the angle in degrees
 * @param length the length of the triangle's hypotenuse
 * @return the integer conversion of length * cos (angle)
 */
public static int cos(int angle, int length) {
	return cast(int)( tango.stdc.math.cos(angle * toRadians) * length);
}

/**
 * Answers the length of the side opposite to the given angle
 * of a right triangle. In other words, it returns the integer
 * conversion of length * sin (angle).
 * <p>
 * IMPORTANT: the j2me version has an additional restriction on
 * the argument. length must be between -32767 and 32767 (inclusive).
 * </p>
 * 
 * @param angle the angle in degrees
 * @param length the length of the triangle's hypotenuse
 * @return the integer conversion of length * sin (angle)
 */
public static int sin(int angle, int length) {
	return cast(int)( tango.stdc.math.sin(angle * toRadians) * length);
}

/**
 * Answers the most negative (i.e. closest to negative infinity)
 * integer value which is greater than the number obtained by dividing
 * the first argument p by the second argument q.
 * 
 * @param p numerator
 * @param q denominator (must be different from zero)
 * @return the ceiling of the rational number p / q.
 */
public static int ceil(int p, int q) {
	return cast(int) tango.stdc.math.ceil(cast(float)p / q);
}

/**
 * Answers the most positive (i.e. closest to positive infinity)
 * integer value which is less than the number obtained by dividing
 * the first argument p by the second argument q.
 *
 * @param p numerator
 * @param q denominator (must be different from zero)
 * @return the floor of the rational number p / q.
 */
public static int floor(int p, int q) {
	return cast(int) tango.stdc.math.floor(cast(double)p / q);
}

/**
 * Answers the result of rounding to the closest integer the number obtained 
 * by dividing the first argument p by the second argument q.
 * <p>
 * IMPORTANT: the j2me version has an additional restriction on
 * the arguments. p must be within the range 0 - 32767 (inclusive).
 * q must be within the range 1 - 32767 (inclusive).
 * </p>
 * 
 * @param p numerator
 * @param q denominator (must be different from zero)
 * @return the closest integer to the rational number p / q
 */
public static int round(int p, int q) {
	return  cast(int) tango.stdc.math.roundl(cast(double)p/cast(double)q);
}

/**
 * Returns 2 raised to the power of the argument.
 *
 * @param n an int value between 0 and 30 (inclusive)
 * @return 2 raised to the power of the argument
 *
 * @exception IllegalArgumentException <ul>
 *    <li>ERROR_INVALID_RANGE - if the argument is not between 0 and 30 (inclusive)</li>
 * </ul>
 */
public static int pow2(int n) {
	if (n >= 1 && n <= 30)
		return 2 << (n - 1);
	else if (n != 0) {
		DWT.error(__FILE__, __LINE__, DWT.ERROR_INVALID_RANGE);
	}
	return 1;
}

/**
 * Open a file if such things are supported.
 * 
 * @param filename the name of the file to open
 * @return a stream on the file if it could be opened.
 * @exception IOException
 */
 /*
public static Stream newFileInputStream(String filename) { // throws IOException {
	File file = null;
	try{
		file = new File(filename.toString(), FileMode.In);
	}catch(FileException e){
		Util.trace(String.fromChar(e.toString()));
	}
	return file;
}
*/

public static OutputStream newFileOutputStream(String filename) {
    return new FileOutputStream(filename);
}

/**
 * Answers whether the character is a letter.
 *
 * @param c the character
 * @return true when the character is a letter
 */
public static boolean isLetter(wchar c) {
	return (c >= 'A' && c <='Z') || (c >= 'a' && c <='z');
}

/**
 * Answers whether the character is a letter or a digit.
 *
 * @param c the character
 * @return true when the character is a letter or a digit
 */
public static boolean isLetterOrDigit(wchar c) {
	return (c >= 'A' && c <='Z') || (c >= 'a' && c <='z') || (c >= '0' && c <='9') ;
}

/**
 * Answers whether the character is a Unicode space character.
 *
 * @param c	 the character
 * @return true when the character is a Unicode space character
 */
public static boolean isSpaceChar(wchar c) {
	return c == ' ';
}

/**
 * Answers whether the character is a whitespace character.
 *
 * @param c the character to test
 * @return true if the character is whitespace
 */
public static boolean isWhitespace(wchar c) {
	return c is ' ' || c is '\t' || c is '\n' || c is '\r';
}

/**
 * Execute a program in a separate platform process if the
 * underlying platform support this.
 * <p>
 * The new process inherits the environment of the caller.
 * </p>
 *
 * @param prog the name of the program to execute
 *
 * @exception IOException
 *  if the program cannot be executed
 * @exception SecurityException
 *  if the current SecurityManager disallows program execution
 */
 // TODO:
//public static void exec(String prog) { // throws java.io.IOException {
//	Runtime.getRuntime().exec(prog);
//}

/**
 * Execute progArray[0] in a separate platform process if the
 * underlying platform support this.
 * <p>
 * The new process inherits the environment of the caller.
 * <p>
 *
 * @param progArray array containing the program to execute and its arguments
 *
 * @exception IOException
 *  if the program cannot be executed
 * @exception	SecurityException
 *  if the current SecurityManager disallows program execution
 */
 // TODO:
//public static void exec(String[] progArray) { // throws java.io.IOException{
//	Runtime.getRuntime().exec(progArray);
//}

// TODO:
//private static ResourceBundle msgs = null;

/**
 * Returns the NLS'ed message for the given argument. This is only being
 * called from DWT.
 * 
 * @param key the key to look up
 * @return the message for the given key
 * 
 * @see DWT#getMessage(String)
 */
public static char[] getMessage(char[] key) {
	char[] answer = key;
	
	if (key is null) {
		DWT.error(__FILE__, __LINE__, DWT.ERROR_NULL_ARGUMENT);
		answer = "";
	}
	// e.g. "SWT_Close" => "Close"
	answer = Converter.replace(answer, "DWT_", "");
// TODO:
//	if (msgs is null) {
//		try {
//			msgs = ResourceBundle.getBundle("org.eclipse.dwt.internal.SWTMessages"); //$NON-NLS-1$
//		} catch (MissingResourceException ex) {
//			answer = key ~ " (no resource bundle)"; //$NON-NLS-1$
//		}
//	}
//	if (msgs !is null) {
//		try {
//			answer = msgs.getString(key);
//		} catch (MissingResourceException ex2) {}
//	}
	Util.trace(__FILE__ , ", line " , __LINE__ , " ~ Under Construction");
	return answer;
}
	
/**
 * Interrupt the current thread. 
 * <p>
 * Note that this is not available on CLDC.
 * </p>
 */
// TODO: 
//public static void interrupt() {
//	Thread.currentThread().interrupt();
//}

/**
 * Compares two instances of class String ignoring the case of the
 * characters and answers if they are equal.
 *
 * @param s1 string
 * @param s2 string
 * @return true if the two instances of class String are equal
 */
//public static boolean equalsIgnoreCase(String s1, String s2) {
//	return std.string.icmp(s1, s2) == 0;
//}

public static void exec(char[] prog) {
	Util.trace(__FILE__ , ", " , __LINE__ , ", Compatibility.exec() not implemented yet");
//	Runtime.getRuntime().exec(prog);
}
}
